#pragma once

#include <functional>
#include <iostream>

#include "xlcomm/base/logger.h"
#include "xlcomm/net/buffer.h"
#include "xlcomm/net/callbacks.h"
#include "xlcomm/net/tcp_connection.h"
using namespace xlcomm;

using StringMessageCallback =
    std::function<void(const net::TcpConnectionPtr& conn,
                       const std::string& msg, Timestamp recv_time)>;

class ChatCodec {  // LengthHeaderCodec
 public:
  ChatCodec(const StringMessageCallback& str_msg_cb)
      : str_msg_cb_(str_msg_cb) {}

  void OnMessage(const net::TcpConnectionPtr& conn, net::Buffer* buff,
                 Timestamp recv_time) {
    while (buff->ReadableBytes() >= kHeaderSize) {
      int len = buff->PeekInt32ToHost();
      if (len > 65536 || len < 0) {
        LOG_ERROR << "Invalid length " << len;
        conn->ForceClose();
        break;
      } else if (static_cast<int>(buff->ReadableBytes()) >= kHeaderSize + len) {
        buff->ReadInt32ToHost();
        std::string msg = buff->ReadString(len);
        if (str_msg_cb_) str_msg_cb_(conn, msg, recv_time);
      } else {
        break;
      }
    }
  }

  void Send(const net::TcpConnectionPtr& conn, const std::string& msg) {
    net::Buffer buff;
    size_t len = msg.length();
    buff.Append(msg);
    buff.PrependInt32ToNet(static_cast<int>(len));
    conn->Send(&buff);
  }

 private:
  static const int kHeaderSize = 4;

  StringMessageCallback str_msg_cb_;
};